﻿// ------------------------------------------------------------------------------
// <copyright file="CharmSetting.cs" company="skumaronline.com">
//    Copyright (C) 2012 Suresh Kumar T.
//
//    This program is free software; you can redistribute it and/or
//    modify it under the terms of the GNU General Public License
//    as published by the Free Software Foundation version 2
//    of the License.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    http://www.gnu.org/licenses/gpl-2.0.html
//
// </copyright>
// ------------------------------------------------------------------------------

namespace StoreAppLib.Controls
{
    using System;
    using System.Collections.Generic;
    using System.Reflection;
    using Windows.UI;
    using Windows.UI.ApplicationSettings;
    using Windows.UI.Popups;
    using Windows.UI.Text;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Media;
    using Windows.UI.Xaml.Media.Imaging;

    /// <summary>
    /// Charm setting class to configure charm setting fly out
    /// </summary>
    public static class CharmSetting
    {
        /// <summary>
        /// Dictionary to store fly outs
        /// </summary>
        private static readonly Dictionary<string, object> Flyouts = new Dictionary<string, object>();
        
        /// <summary>
        /// Indicates whether control is already initialized
        /// </summary>
        private static bool initialized = false;

        /// <summary>
        /// Initializes static members of the <see cref="CharmSetting" /> class.
        /// </summary>
        static CharmSetting()
        {
            CharmSetting.FlyoutWidth = CharmSettingFlyoutWidth.Narrow;
            CharmSetting.BorderThickness = new Thickness(1);
            CharmSetting.HeaderBackgroundColor = Color.FromArgb(255, 0, 77, 96);
            CharmSetting.BackgroundColor = Colors.White;
            CharmSetting.BackButtonForegroundColor = Colors.White;
            CharmSetting.HeaderForegroundColor = Colors.White;
            CharmSetting.HeaderFontSize = 26.667;
            CharmSetting.HeaderFontStyle = FontStyle.Normal;
            CharmSetting.HeaderFontFamily = new FontFamily("Segoe UI");

            TranslateTransform transform = new TranslateTransform();
            transform.X = -1;
            transform.Y = 6;
            CharmSetting.HeaderRenderTransform = transform;

            CharmSetting.Icon = new BitmapImage(new Uri("ms-appx:///Assets/SmallLogo.png"));
            CharmSetting.Animation = CharmSettingAnimation.Flyout;
        }

        /// <summary>
        /// Gets or sets fly out width
        /// </summary>
        public static CharmSettingFlyoutWidth FlyoutWidth { get; set; }

        /// <summary>
        /// Gets or sets fly out boarder
        /// </summary>
        public static Thickness BorderThickness { get; set; }

        /// <summary>
        /// Gets or sets header background color
        /// </summary>
        public static Color HeaderBackgroundColor { get; set; }

        /// <summary>
        /// Gets or sets header font family
        /// </summary>
        public static FontFamily HeaderFontFamily { get; set; }

        /// <summary>
        /// Gets or sets header font size
        /// </summary>
        public static double HeaderFontSize { get; set; }

        /// <summary>
        /// Gets or sets header foreground color
        /// </summary>
        public static Color HeaderForegroundColor { get; set; }

        /// <summary>
        /// Gets or sets header font style
        /// </summary>
        public static FontStyle HeaderFontStyle { get; set; }

        /// <summary>
        /// Gets or sets header font render transform
        /// </summary>
        public static Transform HeaderRenderTransform { get; set; }

        /// <summary>
        /// Gets or sets back button foreground color
        /// </summary>
        public static Color BackButtonForegroundColor { get; set; }

        /// <summary>
        /// Gets or sets content area color
        /// </summary>
        public static Color BackgroundColor { get; set; }

        /// <summary>
        /// Gets or sets small logo icon in header area
        /// </summary>
        public static ImageSource Icon { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether entrance animation is for content or for fly out
        /// </summary>
        public static CharmSettingAnimation Animation { get; set; }

        /// <summary>
        /// Add user control to charm setting.
        /// </summary>
        /// <param name="label">The label for the command, which is displayed in the settings pane</param>
        /// <param name="charmFlyoutType">Type of the user control to be displayed when selecting</param>
        public static void AddFlyout(string label, Type charmFlyoutType)
        {
            CharmSetting.Initialize();

            if (typeof(UserControl).GetTypeInfo().IsAssignableFrom(charmFlyoutType.GetTypeInfo()))
            {
                CharmSetting.Flyouts.Add(label, charmFlyoutType);
            }
            else
            {
                throw new InvalidCastException(string.Format("Cannot create charm flyout from type {0}.\ncharmFlyoutType argument must be a UserControl derived class type", charmFlyoutType.FullName));
            }
        }       

        /// <summary>
        /// Add charm setting command for custom handling
        /// </summary>
        /// <param name="label">The label for the command, which is displayed in the settings pane</param>
        /// <param name="handler">The event handler that is called when the user selects this command in the settings pane</param>
        public static void AddFlyout(string label, UICommandInvokedHandler handler)
        {
            CharmSetting.AddFlyout(null, label, handler);
        }

        /// <summary>
        /// Add charm setting command for custom handling
        /// </summary>
        /// <param name="settingsCommandId">The ID of the command</param>
        /// <param name="label">The label for the command, which is displayed in the settings pane</param>
        /// <param name="handler">The event handler that is called when the user selects this command in the settings pane</param>
        public static void AddFlyout(object settingsCommandId, string label, UICommandInvokedHandler handler)
        {
            Setting setting;

            setting.CommandId = settingsCommandId;
            setting.Hadler = handler;

            CharmSetting.Initialize();

            CharmSetting.Flyouts.Add(label, setting);
        }

        /// <summary>
        /// Removes the charm setting fly outs added
        /// </summary>
        public static void Clear()
        {
            CharmSetting.Flyouts.Clear();
        }

        /// <summary>
        /// Initialize the setting
        /// </summary>
        private static void Initialize()
        {
            if (!CharmSetting.initialized)
            {
                CharmSetting.initialized = true;
                SettingsPane.GetForCurrentView().CommandsRequested += OnSettingPaneCommandsRequested;
            }
        }

        /// <summary>
        /// Fires when user select setting from  charm bar
        /// </summary>
        /// <param name="sender">The sender</param>
        /// <param name="args">The argument</param>
        private static void OnSettingPaneCommandsRequested(SettingsPane sender, SettingsPaneCommandsRequestedEventArgs args)
        {
            foreach (var item in CharmSetting.Flyouts)
            {
                SettingsCommand command = new SettingsCommand(item.Value, item.Key, new UICommandInvokedHandler(CharmSetting.OnSettingCommandInvoked));
                args.Request.ApplicationCommands.Add(command);
            }
        }

        /// <summary>
        /// Fires when user select a charm fly out from setting pane
        /// </summary>
        /// <param name="command">The UI command</param>
        private static void OnSettingCommandInvoked(IUICommand command)
        {
            if (command.Id is Setting)
            {
                Setting setting = (Setting)command.Id;

                if (setting.Hadler != null)
                {
                    setting.Hadler.Invoke(new UICommand(command.Label, setting.Hadler, setting.CommandId));
                }
            }
            else
            {
                Type flyoutType = command.Id as Type;

                if (flyoutType != null)
                {
                    UserControl content = Activator.CreateInstance(flyoutType) as UserControl;

                    CharmSettingFlyout settingFlyout = new CharmSettingFlyout(content, CharmSetting.Animation);

                    settingFlyout.FlyoutWidth = CharmSetting.FlyoutWidth;
                    settingFlyout.BorderThickness = CharmSetting.BorderThickness;
                    settingFlyout.BorderBrush = new SolidColorBrush(CharmSetting.DarkColor(CharmSetting.HeaderBackgroundColor, -0.2f));
                    settingFlyout.HeaderBackground = new SolidColorBrush(CharmSetting.HeaderBackgroundColor);
                    settingFlyout.HeaderForeground = new SolidColorBrush(CharmSetting.HeaderForegroundColor);
                    settingFlyout.BackButtonForeground = new SolidColorBrush(CharmSetting.BackButtonForegroundColor);
                    settingFlyout.HeaderFontSize = CharmSetting.HeaderFontSize;
                    settingFlyout.HeaderFontStyle = CharmSetting.HeaderFontStyle;
                    settingFlyout.HeaderFontFamily = CharmSetting.HeaderFontFamily;
                    settingFlyout.HeaderRenderTransform = CharmSetting.HeaderRenderTransform;
                    settingFlyout.Background = new SolidColorBrush(CharmSetting.BackgroundColor);
                    settingFlyout.HeaderText = command.Label;
                    settingFlyout.Icon = CharmSetting.Icon;

                    settingFlyout.Open();
                }
            }
        }

        /// <summary>
        /// Make a color darker
        /// </summary>
        /// <param name="color">The color to be darkened</param>
        /// <param name="factor">The factor by which darkened</param>
        /// <returns>The darker color</returns>
        private static Color DarkColor(Color color, float factor)
        {
            float red = Math.Max((color.R * factor) + color.R, 0);
            float green = Math.Max((color.G * factor) + color.G, 0);
            float blue = Math.Max((color.B * factor) + color.B, 0);
            return Color.FromArgb(color.A, (byte)red, (byte)green, (byte)blue);
        }

        /// <summary>
        /// Setting struct to hold setting command values
        /// </summary>
        private struct Setting
        {
            /// <summary>
            /// Command Id
            /// </summary>
            public object CommandId;

            /// <summary>
            /// Call back handler
            /// </summary>
            public UICommandInvokedHandler Hadler;
        }
    }
}
